package com.bawei.es.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.bawei.es.domain.IndexInfoResp;
import com.bawei.es.service.EsIndexService;
import com.bawei.es.domain.IndexEntry;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author : zhangyu
 * @date 2023/11/13 15:24
 */
@Slf4j
@Service
@AllArgsConstructor
public class EsIndexServiceImpl implements EsIndexService {

    private RestHighLevelClient restHighLevelClient;

    /**
     * 创建索引
     *
     * @param indexEntry 索引条目
     */
    @Override
    public void createIndex(IndexEntry indexEntry) {
        log.info("创建索引:{}", JSONObject.toJSONString(indexEntry));
        boolean exists = isExists(indexEntry.getIndexName());
        if (exists) {
            throw new RuntimeException("索引:" + indexEntry.getIndexName() + "已经存在");

        }// 索引不存在，则创建索引
        try {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexEntry.getIndexName());
        // 检查是否存在映射配置，如果存在则设置映射
        if (indexEntry.getMapping() != null) {
            String mappingJson = JSONObject.toJSONString(indexEntry.getMapping());
          log.info("mapping转JSON内容：{}",mappingJson);
            createIndexRequest.mapping(indexEntry.getIndexName(),mappingJson, XContentType.JSON);
        }
            restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
            // 使用 REST 高级客户端创建索引
        } catch (IOException e) {
            throw new RuntimeException("创建索引失败", e);
        }
    }


    /**
     * 删除索引
     *
     * @param indexName 索引名称
     */
    @Override
    public void deleteIndex(String indexName) {
        // 检查索引是否存在
        boolean exists = isExists(indexName);
        if (!exists) {
            // 若索引不存在则抛出运行时异常
            throw new RuntimeException("索引:" + indexName + "不存在");

        }
        try {
            // 创建删除索引请求对象
            DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
            // 设置主节点超时时间为索引名
//                deleteIndexRequest.masterNodeTimeout(indexName);
            // 调用HighLevelRestClient的indices().delete()方法删除索引
            restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("删除索引:{}", indexName);

    }


        /**
     * 判断指定的索引是否存在。
     *
     * @param indexName 索引名称
     * @return 存在返回true，否则返回false
     */
    @Override
    public boolean isExists(String indexName) {
        // 创建查询索引的请求对象
        GetIndexRequest request = new GetIndexRequest(indexName);
        try {
            // 查询索引是否存在，返回布尔值
            boolean exist = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
            return exist;
        } catch (IOException e) {
            // 封装运行时异常，查询索引失败时抛出
            throw new RuntimeException("查询索引失败", e);
        }
    }


    /**
     * 获取指定索引的详细信息
     *
     * @param indexName 索引名称
     * @return 索引的详细信息
     */
    @Override
    public IndexInfoResp getIndex(String indexName) {
        // 判断索引是否存在
        boolean exists = isExists(indexName);
        if (exists) {
            // 如果索引存在，构建查询请求
            GetIndexRequest request = new GetIndexRequest(indexName);
            try {
                // 构建返回对象
                IndexInfoResp indexInfoResp = new IndexInfoResp();
                // 发起Elasticsearch查询
                GetIndexResponse getIndexRequest = restHighLevelClient.indices().get(request, RequestOptions.DEFAULT);
                // 获取索引名称并设置到返回对象中
                indexInfoResp.setIndexName(getIndexRequest.getIndices()[0]);
                // 获取映射信息，并设置到返回对象中
                indexInfoResp.setMappings(getIndexRequest.getMappings().get(indexName).getSourceAsMap());
                // 获取设置信息，并设置到返回对象中
                Settings settings = getIndexRequest.getSettings().get(indexName);
                Set<String> strings = settings.keySet();
                Map<String, Object> map = new HashMap<>();
                // 遍历设置信息，转为map形式并设置到返回对象中
                strings.forEach(key -> {
                    map.put(key, settings.get(key));
                });
                indexInfoResp.setSettings(map);
                // 获取别名信息，并设置到返回对象中
                Map<String, List<AliasMetadata>> aliases = getIndexRequest.getAliases();
                Map<String, Object> aliasMap = JSONObject.parseObject(JSONObject.toJSONString(aliases), Map.class);
                indexInfoResp.setAliases(aliasMap);

                // 返回索引信息对象
                return indexInfoResp;
            } catch (Exception e) {
                // 抛出运行时异常，指示查询索引失败
                throw new RuntimeException("查询索引失败", e);
            }
        } else {
            // 如果索引不存在，抛出运行时异常
            throw new RuntimeException("索引不存在");
        }
    }

        /**
     * 更新索引映射
     *
     * @param indexEntry 索引映射条目
     */
    @Override
    public void updateIndex(IndexEntry indexEntry) {

        // 检查索引是否存在
        boolean exists = isExists(indexEntry.getIndexName());
        if (!exists) {
            throw new RuntimeException("es索引" + indexEntry.getIndexName() + "不存在");
        }

        try {
            // 创建PutMappingRequest对象
            PutMappingRequest putMappingRequest = new PutMappingRequest(indexEntry.getIndexName());
            // 将Mapping对象转换为JSON字符串
            String jsonString = JSONObject.toJSONString(indexEntry.getMapping());
            putMappingRequest.source(jsonString,XContentType.JSON);

            // 使用restHighLevelClient将映射更新到索引
            restHighLevelClient.indices().putMapping(putMappingRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            // 捕获IOException异常并抛出RuntimeException异常
            throw new RuntimeException("更新索引失败" + JSONObject.toJSONString(indexEntry));
        }

        // 输出日志，索引更新成功
        log.info("更新索引成功");
    }




}
